/*
 * Copyright 2014 Щекотова Ангелина Александровна.
 * Этот файл — часть J4JClientServer Framework
 * J4JClientServer Framework - свободная программа: вы можете перераспространять ее и/или изменять
 * ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде, в каком
 * она была опубликована Фондом свободного программного обеспечения; либо
 * версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
 *
 * J4JClientServer Framework распространяется в надежде, что она будет полезной,
 * но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
 * или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
 * общественной лицензии GNU.
 *
 * Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
 * вместе с этой программой. Если это не так, см.
 * <http://www.gnu.org/licenses/>.
 */

package ru.java4java.utils;

import java.io.Serializable;

public class Counter implements Serializable, Cloneable {

    private long min;
    private long max;
    private long value;
    private boolean autoReset = false;

    public Counter(long min, long max) {
        this.min = min;
        this.max = max;
        this.value = min;
    }

    public long getMax() { return max; }
    public Counter setMax(long max) { this.max = max; return this; }

    public long getMin() { return min; }
    public Counter setMin(long min) { this.min = min; return this; }

    public Counter setValue(long value) { this.value = value; autoReset(); return this; }
    public long getValue() { return value; }
    public Counter reset() { value = min; return this; }
    public Counter increment() { value++; autoReset(); return this; }
    public Counter decrement() { value--; autoReset(); return this; }

    public boolean isOverload() { return value > max; }
    public boolean isUnderload() { return value < min; }

    public long overload() { return isOverload() ? value - max : 0; }
    public long underload() { return isUnderload() ? min - value : 0; }

    public Counter autoReset(boolean flag) { autoReset = flag; return this; }

    @Override
    public Counter clone() throws CloneNotSupportedException {
        super.clone();
        Counter counter = new Counter(this.min, this.max);
        counter.value = this.value;
        counter.autoReset = this.autoReset;
        return counter;
    }

    private void autoReset() {
        if (!autoReset) return;
        if (value > max) {
            value = min;
            return;
        }
        if (value < min) {
            value = max;
        }
    }

    public static Timer runTimer() {
        Timer timer = new Timer();
        timer.start();
        return timer;
    }

    public static class Timer implements Serializable, Cloneable {

        private long start;
        private long difference;

        public Timer() {
            this.start = -1;
            this.difference = -1;
        }

        public Timer start() {
            if (start == -1) {
                start = System.currentTimeMillis();
            }
            difference = -1;
            return this;
        }

        public Timer stop() {
            difference = start - System.currentTimeMillis();
            start = -1;
            return this;
        }

        public long difference() {
            if (start < 0 && difference < 0) return -1;
            if (start >= 0 && difference < 0) {
                return System.currentTimeMillis() - start;
            } else {
                return difference;
            }
        }

        public Timer resetTimer() {
            start = -1;
            difference = -1;
            return this;
        }

        @Override
        public Timer clone() throws CloneNotSupportedException {
            super.clone();
            Timer timer = new Timer();
            timer.start = this.start;
            timer.difference = this.difference;
            return timer;
        }

    }


    public static AutoTimer runAutoTimer(TimerListener listener, long interval) {
        AutoTimer autoTimer = new AutoTimer(listener, interval);
        Thread thread = new Thread(autoTimer);
        thread.start();
        return autoTimer;
    }

    public static AutoTimer runOneOffAutoTimer(TimerListener listener, long interval) {
        AutoTimer autoTimer = new AutoTimer(listener, interval);
        autoTimer.oneOff(true);
        Thread thread = new Thread(autoTimer);
        thread.start();
        return autoTimer;
    }


    public static class AutoTimer implements Runnable, Cloneable {

        private final TimerListener listener;
        private long interval;
        private boolean stop;
        private boolean oneOff = false;

        public AutoTimer(TimerListener listener, long interval) {
            this.listener = listener;
            this.interval = interval;
        }

        public AutoTimer oneOff(boolean oneOff) {
            this.oneOff = oneOff;
            this.stop();
            return this;
        }

        public boolean isOneOff() { return oneOff; }

        public void setInterval(long interval) { this.interval = interval; }

        public long getInterval() { return interval; }

        @Override
        public void run() {
            stop = oneOff;
            long start = System.currentTimeMillis();
            do {
                if (System.currentTimeMillis() - start >= interval) {
                    start = System.currentTimeMillis();
                    listener.tick(this);
                }
            } while (!stop);
        }

        public AutoTimer stop() { stop = true; return this; }

        @Override
        public AutoTimer clone() throws CloneNotSupportedException {
            super.clone();
            AutoTimer timer = new AutoTimer(this.listener, this.interval);
            timer.stop = this.stop;
            timer.oneOff = this.oneOff;
            return timer;
        }

    }

    public static interface TimerListener {

        public void tick(AutoTimer timer);

    }


}
